package is2.minga.packetProcessor.authentificator;

import is2.misc.pipeAndFilter.*;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.net.Socket;

import java.util.Iterator;
import java.util.Random;
import java.util.Set;
import java.util.TreeSet;

import org.json.JSONObject;


import base64.Base64;



public class MingaAuthentificator implements Filter<String, String>
{
	private String hostSeed;
	private Integer portSeed;
	
	public MingaAuthentificator()
	{
		String FILE_SEED = "config/codeTranceptorLocation.txt";

		try {
			
			FileInputStream fstream = new FileInputStream(FILE_SEED);
			
		    DataInputStream in = new DataInputStream(fstream);
		    BufferedReader br = new BufferedReader(new InputStreamReader(in));
		    String strLine;
		      
		    strLine = br.readLine();
	
		    String[] s = strLine.split(",");
		    hostSeed = s[0];
		    portSeed = Integer.parseInt(s[1]);
		    
		    in.close();
		} catch (Exception e) {
			System.out.println("autenticator no puede leer code tranceptor location");
		}
	
	}
	
	
	public String filter(String in) throws Exception
	{
		
		
		try {
			Set<Long> semillas = obtenerSemillas();
			boolean bValido = false;
			Iterator<Long> it =  semillas.iterator();
		
			JSONObject data = new JSONObject(in);
			byte numSeq = (byte) data.getInt("numSeq");
			byte numSeqEnc =(byte) data.getInt("numSeqEnc");
			byte[] datos = Base64.decode(data.getString("datos"));
			byte ruido = 0;
		
			while (it.hasNext() && !bValido)
			{
				ruido = obtenerRuido(it.next(), numSeq);
				if ((ruido ^ numSeq) == numSeqEnc)
				{
					bValido = true;
				}
			}
			
			if (!bValido)
			{
				throw (new Exception("autenticator: mensaje invalido"));
			}
					
			String datosDec = "";
			
			for (int i = 0; i < datos.length; i++)
			{
				byte b = (byte) (datos[i] ^ ruido);
				char d = (char) b;
				datosDec = datosDec + d;
			}
			
			data.remove("datos");
			data.put("datos", datosDec);
			
			return data.toString();
	
		} catch (Exception e) {
		
			System.out.println(e.toString());
			throw (new Exception("Minga Authenticator descartando mensaje"));
		}
	
	}
	

/*	private Set<Long> obtenerSemillas() throws Exception
	{
		// en principio se leen las cosas desde un archivo de texto (podria
		// reemplazarse por el Code Tranceptor si es que lo implementamos luego)
		// si el archivo no esta, devuelve una excepcion
		
		String FILE_SEED = "D:/Facultad/IS2/tp1 parte2/semilla.txt";
		
		Set<Long> semillas = new TreeSet<Long>();

		try
		{
		
			FileInputStream fstream = new FileInputStream(FILE_SEED);
			
		    DataInputStream in = new DataInputStream(fstream);
		    BufferedReader br = new BufferedReader(new InputStreamReader(in));
		    String strLine;
		      
		    strLine = br.readLine();

		    String[] s = strLine.split(",");
		    for (int i = 0; i < s.length; i++)
		    {
			    semillas.add(Long.parseLong(s[i]));
		    	
		    }
		    in.close();
			

		} catch (Exception e) {
	
			System.out.println("");
			throw (new Exception("No se puede obtener la semilla"));
			
		}

		return semillas;
	}
	
	*/
	
	
	private Set<Long> obtenerSemillas() throws Exception
	{

		
		Set<Long> semillas = new TreeSet<Long>();

		try
		{
			System.out.println("autenticator: obteniendo nuevas semillas");
			Socket clientSocket = new Socket(hostSeed, portSeed);
			BufferedReader inFromClient = new BufferedReader(new
					InputStreamReader(clientSocket.getInputStream())); 
				
			String strLine = inFromClient.readLine();
			if (strLine == null)
			{
				throw (new Exception());
			}
			
		    String[] s = strLine.split(",");
		    for (int i = 0; i < s.length; i++)
		    {
			    semillas.add(Long.parseLong(s[i]));
		    	
		    }

		    
		    System.out.println("autenticator: semillas obtenidas");

		} catch (Exception e) {
	
			System.out.println("");
			throw (new Exception("No se puede obtener la semilla:" + e.toString()));
			
		}

		return semillas;
	}

	
	
	byte obtenerRuido(Long semilla, byte numSeq)
	{
		byte ruido;
		
		Random r = new Random();
		r.setSeed(semilla);
		
		for (int i = 0; i < numSeq - 1; i++)
		{
			r.nextLong();
		}
		ruido = (byte) r.nextLong();

		return ruido;
	}
	
}
